package cn.labbook.bluetooth.service.impl;

import cn.labbook.bluetooth.common.MyPage;
import cn.labbook.bluetooth.entity.*;
import cn.labbook.bluetooth.exception.SysException;
import cn.labbook.bluetooth.mapper.ApplyRecordMapper;
import cn.labbook.bluetooth.pojo.dto.ApplyRecordDTO;
import cn.labbook.bluetooth.service.IAdminService;
import cn.labbook.bluetooth.service.IAmmeterService;
import cn.labbook.bluetooth.service.IApplyRecordService;
import cn.labbook.bluetooth.util.DoubleUtils;
import cn.labbook.bluetooth.util.StringUtils;
import cn.labbook.bluetooth.util.TimeUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * @Author: zhangyang
 * @Date: 2023/4/13 14:40
 * @Desc: 申请记录 service 实现
 */
@Service
public class ApplyRecordServiceImpl extends ServiceImpl<ApplyRecordMapper, ApplyRecord> implements IApplyRecordService {

    @Autowired
    private IAmmeterService ammeterService;
    @Autowired
    private IAdminService adminService;


    @Override
    public void create(String ammeterId, String openId, String totalFee) {
        Ammeter ammeter = ammeterService.getById(ammeterId);
        if (Objects.isNull(ammeter)) {
            return;
        }

        double totalFeeValue = Double.parseDouble(totalFee);
        double amount = totalFeeValue / 100;
        double protectPrice = ammeterService.getProtectPrice(ammeter.getProtectPrice());
        if (DoubleUtils.leZero(ammeter.getBalance()) && amount < protectPrice) {
            throw new SysException("申请金额不能小于保电金额");
        }

        ApplyRecord applyRecord = new ApplyRecord();
        applyRecord.setOpenId(openId);
        applyRecord.setAmmeterId(ammeter.getAmmeterId());
        applyRecord.setLocation(ammeter.getLocation());
        applyRecord.setAmount(amount);

        Double rate = this.getPayRate(ammeter.getAdminId());
        BigDecimal rate_bv = new BigDecimal(rate).divide(new BigDecimal(100), 4, RoundingMode.HALF_UP);
        BigDecimal zkisPlatformAmount = (new BigDecimal(totalFeeValue).multiply(rate_bv)).divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
        applyRecord.setZkisPlatformAmount(zkisPlatformAmount.doubleValue());

        double payTrueAmount = amount;
        if (DoubleUtils.leZero(ammeter.getBalance())) {
            payTrueAmount =  amount - protectPrice;
        }
        applyRecord.setPayTrueAmount(payTrueAmount);
        applyRecord.setCreateTime(new Date());

        Integer status = ApplyRecord.Status.IN.getKey();
        if (payTrueAmount <= 0) {
            status = ApplyRecord.Status.COMPLETE.getKey();
        }
        applyRecord.setStatus(status);
        applyRecord.setSyncStatus(ApplyRecord.SyncStatus.WAIT.getKey());
        applyRecord.setIsSkimp(ammeter.getIsSkimp());
        applyRecord.setType(ApplyRecord.Type.APPLY.getKey());
        save(applyRecord);

        // 生成保电记录
        createProtectRecord(applyRecord, ammeter.getBalance(), protectPrice);
    }

    private void createProtectRecord(ApplyRecord applyRecord, Double balance, Double protectPrice) {
        if (DoubleUtils.gtZero(balance)) {
            return;
        }
        ApplyRecord protectRecord = new ApplyRecord();
        protectRecord.setOpenId(applyRecord.getOpenId());
        protectRecord.setAmmeterId(applyRecord.getAmmeterId());
        protectRecord.setLocation(applyRecord.getLocation());
        protectRecord.setAmount(protectPrice);
        protectRecord.setPayTrueAmount(protectPrice);
        protectRecord.setZkisPlatformAmount(0d);
        protectRecord.setCreateTime(new Date());
        protectRecord.setStatus(ApplyRecord.Status.COMPLETE.getKey());
        protectRecord.setSyncStatus(ApplyRecord.SyncStatus.WAIT.getKey());
        protectRecord.setIsSkimp(applyRecord.getIsSkimp());
        protectRecord.setType(ApplyRecord.Type.PROTECT.getKey());
        save(protectRecord);
    }

    @Override
    public Double getPayRate(String adminId) {
        LambdaQueryWrapper<Admin> wrapper = new QueryWrapper<Admin>().lambda();
        wrapper.eq(Admin::getAdminId, adminId);
        Admin admin = adminService.getOne(wrapper);
        return admin.getPayRate();
    }

    @Override
    public void create(ApplyPay applyPay) {
        ApplyRecord applyRecord = new ApplyRecord();
        applyRecord.setOpenId(applyPay.getOpenId());
        applyRecord.setAmmeterId(applyPay.getAmmeterId());
        applyRecord.setLocation(applyPay.getLocation());
        applyRecord.setAmount(applyPay.getAmount());
        applyRecord.setPayTrueAmount(applyPay.getPayTrueAmount());
        applyRecord.setZkisPlatformAmount(applyPay.getZkisPlatformAmount());
        applyRecord.setCreateTime(new Date());
        applyRecord.setStatus(ApplyRecord.Status.IN.getKey());
        applyRecord.setSyncStatus(ApplyRecord.SyncStatus.WAIT.getKey());
        applyRecord.setIsSkimp(applyPay.getIsSkimp());
        applyRecord.setType(ApplyRecord.Type.APPLY.getKey());
        save(applyRecord);

        // 生成保电记录
        createProtectRecord(applyPay);
    }

    private void createProtectRecord(ApplyPay applyPay) {
        if (DoubleUtils.leZero(applyPay.getProtectPrice())) {
            return;
        }
        ApplyRecord applyRecord = new ApplyRecord();
        applyRecord.setOpenId(applyPay.getOpenId());
        applyRecord.setAmmeterId(applyPay.getAmmeterId());
        applyRecord.setLocation(applyPay.getLocation());
        applyRecord.setAmount(applyPay.getProtectPrice());
        applyRecord.setPayTrueAmount(applyPay.getProtectPrice());
        applyRecord.setZkisPlatformAmount(0d);
        applyRecord.setCreateTime(new Date());
        applyRecord.setStatus(ApplyRecord.Status.COMPLETE.getKey());
        applyRecord.setSyncStatus(ApplyRecord.SyncStatus.WAIT.getKey());
        applyRecord.setIsSkimp(applyPay.getIsSkimp());
        applyRecord.setType(ApplyRecord.Type.PROTECT.getKey());
        save(applyRecord);
    }

    @Override
    public void handle(Integer id) {
        updateStatus(id, ApplyRecord.Status.COMPLETE.getKey());
    }

    private void updateStatus(Integer id, Integer status) {
        ApplyRecord applyRecord = getById(id);
        if (Objects.isNull(applyRecord)) {
            return;
        }
        applyRecord.setStatus(status);
        updateById(applyRecord);
    }

    @Override
    public void back(Integer id) {
        updateStatus(id, ApplyRecord.Status.BACK.getKey());
    }

    @Override
    public ApplyRecord getWaitSync(String openId, String ammeterId) {
        LambdaQueryWrapper<ApplyRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ApplyRecord::getStatus, ApplyRecord.Status.COMPLETE.getKey());
        wrapper.eq(ApplyRecord::getSyncStatus, ApplyRecord.SyncStatus.WAIT.getKey());
//        wrapper.eq(ApplyRecord::getOpenId, openId);
        wrapper.eq(ApplyRecord::getAmmeterId, ammeterId);
        return getOne(wrapper);
    }

    @Override
    public List<ApplyRecordDTO> listWithLandlord(String Date, String userId, MyPage<ApplyRecord> page) {
        QueryWrapper<ApplyRecord> wrapper = new QueryWrapper<>();
        if(StringUtils.isNotBlank(Date)) {
            wrapper.likeRight("apply.create_time", Date);
        } else {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
            wrapper.likeRight("apply.create_time", sdf.format(new Date()));
        }
        wrapper.eq("apply.type", ApplyRecord.Type.APPLY.getKey())
                .eq("amm.manager_id", userId)
                .orderByDesc("apply.create_time");

        List<Integer> statusList = new ArrayList<>();
        statusList.add(ApplyRecord.Status.IN.getKey());
        statusList.add(ApplyRecord.Status.COMPLETE.getKey());
        wrapper.in("apply.status", statusList);

        List<ApplyRecordDTO> finalDtoList = new ArrayList<>();
        List<ApplyRecordDTO> dtoList = this.baseMapper.listWithLandlord(wrapper, page);
        for (ApplyRecordDTO dto : dtoList) {
            dto.setStatusStr(ApplyRecord.Status.getValueByKey(dto.getStatus()));
            dto.setCreateTimeStr(TimeUtils.dateFormat(dto.getCreateTime(), "yyyy-MM-dd HH:mm:ss"));
            dto.setAmount(BigDecimal.valueOf(dto.getAmount()).setScale(2, RoundingMode.HALF_UP).doubleValue());

            finalDtoList.add(dto);
        }
        return finalDtoList;
    }

    @Override
    public List<ApplyRecordDTO> listWithTenant(String Date, String openId, MyPage<ApplyRecord> page) {
        QueryWrapper<ApplyRecord> wrapper = new QueryWrapper<>();
        if(StringUtils.isNotBlank(Date)) {
            wrapper.likeRight("apply.create_time",Date);
        } else {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
            wrapper.likeRight("apply.create_time",sdf.format(new Date()));
        }
        wrapper.eq("apply.type", ApplyRecord.Type.APPLY.getKey())
                .eq("apply.open_id", openId)
                .orderByDesc("apply.create_time");

        List<ApplyRecordDTO> finalDtoList = new ArrayList<>();
        List<ApplyRecordDTO> dtoList = this.baseMapper.listWithLandlord(wrapper, page);
        for (ApplyRecordDTO dto : dtoList) {
            dto.setStatusStr(ApplyRecord.Status.getValueByKey(dto.getStatus()));
            dto.setCreateTimeStr(TimeUtils.dateFormat(dto.getCreateTime(), "yyyy-MM-dd HH:mm:ss"));
            dto.setAmount(BigDecimal.valueOf(dto.getAmount()).setScale(2, RoundingMode.HALF_UP).doubleValue());

            finalDtoList.add(dto);
        }
        return finalDtoList;
    }

    @Override
    public List<ApplyRecord> getSumPay(String Date, String userId, String openId) {
        QueryWrapper<ApplyRecord> wrapper = new QueryWrapper<>();
        if(StringUtils.isNotBlank(Date)){
            wrapper.likeRight("apply.create_time",Date);
        }else {
            SimpleDateFormat sdf =new SimpleDateFormat("yyyy-MM");
            wrapper.likeRight("apply.create_time",sdf.format(new Date()));
        }
        if (StringUtils.isNotBlank(userId)) {
            wrapper.eq("amm.manager_id", userId);
        }
        if (StringUtils.isNotBlank(openId)) {
            wrapper.eq("apply.open_id", openId);
        }
        return this.baseMapper.getSumPay(wrapper);
    }

    @Override
    public boolean exist(String openId, Integer status) {
        LambdaQueryWrapper<ApplyRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ApplyRecord::getOpenId, openId);
        wrapper.eq(ApplyRecord::getStatus, status);
        return count(wrapper) != 0;
    }

    @Override
    public boolean existIn(String userId) {
        QueryWrapper<ApplyRecord> wrapper = new QueryWrapper<>();
        wrapper.eq("apply.type", ApplyRecord.Type.APPLY.getKey())
                .eq("apply.status", ApplyRecord.Status.IN.getKey())
                .eq("amm.manager_id", userId);

        Integer count = this.baseMapper.countWithLandlord(wrapper);
        return count != 0;
    }

}
